package com.spark.tags;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.spark.core.SparkBuilder;
import com.spark.core.SparkContext;
import com.spark.core.XMap;


/**
 * 
 * @version $Id: Grid.java v 1.0 2010-1-25 下午01:30:09 znjqolf Exp $
 * @author <a href="mailto:znjqolf@126.com">vincent</a>
 */
public class Grid extends ViewComponent {
	
	private static final String DEFAULT_TEMPLATES = "grid.ftl";
	
	public static final String HTML_LOCKAREA = "lockArea";
	public static final String HTML_UNLOCKAREA = "unlockArea";
	
	private static final int DEFALUT_HEAD_HEIGHT = 25;
	private static final int COLUMN_WIDTH = 100;
	
	private static final String DEFAULT_CLASSNAME = "s-grid-wrap";
	private static final String MAX_ROWS = "maxRow";
	private static final String ROW_SPAN = "rowspan";
	private static final String COL_SPAN = "colspan";
	private static final String ROW_HEIGHT = "rowHeight";
	private static final String HEAD_HEIGHT = "headHeight";
	private static final String LOCK_WIDTH = "lockWidth";
	private static final String UNLOCK_WIDTH = "unlockWidth";
	private static final String BODY_HEIGHT = "bodyHeight";
	private static final String TABLE_HEIGHT = "tableHeight";
	private static final String FOOTER_BAR = "footerBar";
	private static final String LOCK_COLUMNS = "lockcolumns";
	private static final String UNLOCK_COLUMNS = "unlockcolumns";
	
	private static final String COLUMN_TYPE = "type";
	private static final String TYPE_CELL_CHECKBOX = "cellcheck";
//	private static final String TYPE_CELL_RADIO = "cellradio";
	private static final String TYPE_ROW_CHECKBOX = "rowcheck";
	private static final String TYPE_ROW_RADIO = "rowradio";
	private static final String TYPE_ROW_NUMBER = "rownumber";
	
	public static final String PROPERTITY_AUTO_PAGE_SIZE = "autoPageSize";
	public static final String PROPERTITY_FOCUS_ROW = "focusRow";
	public static final String PROPERTITY_LISTEN_MOUSE_WHEEL = "listenMouseWheel";
	public static final String PROPERTITY_SHOW_HEAD = "showHead";
	public static final String PROPERTITY_STRIPE_ROWS = "stripeRows";
	public static final String PROPERTITY_COLUMNS = "columns";
//	public static final String PROPERTITY_EDITOR = "editor";
	public static final String PROPERTITY_EDITORS = "editors";
	public static final String PROPERTITY_TOOLBAR = "toolBar";
	public static final String PROPERTITY_DATASET = "dataset";
	public static final String PROPERTITY_NAVBAR = "navBar";
	public static final String PROPERTITY_AUTO_FOCUS = "autoFocus";
	public static final String PROPERTITY_ROW_RENDERER = "rowRenderer";
	public static final String PROPERTITY_SHOW_ROWNUMBER = "showRowNumber";
	public static final String PROPERTITY_LOCK_ROWBOX = "lockRowBox";//是否锁定checkbox,radiobox,rownum
	
	public static final String COLUMN_PROPERTITY_ADAPTIVE = "adaptive";
	public static final String COLUMN_PROPERTITY_NAME = "name";
	public static final String COLUMN_PROPERTITY_EDITOR = "editor";
	public static final String COLUMN_PROPERTITY_ALIGN = "align";
	public static final String COLUMN_PROPERTITY_LOCK = "lock";
	public static final String COLUMN_PROPERTITY_HIDDEN = "hidden";
	public static final String COLUMN_PROPERTITY_RESIZABLE = "resizable";
	public static final String COLUMN_PROPERTITY_SHOW_TITLE = "showTitle";
	public static final String COLUMN_PROPERTITY_RENDERER = "renderer";
	public static final String COLUMN_PROPERTITY_FOOTER_RENDERER = "footerRenderer";
	public static final String COLUMN_PROPERTITY_SORTABLE = "sortable";
	private static final String DEFAULT_COLUMN_ALIGN = "left";
	
	public String getTemplate(){
		return DEFAULT_TEMPLATES;
	}
	
	protected String getDefaultClass(XMap view,SparkContext context){
		String className = super.getDefaultClass(view, context);
		StringBuilder sb = new StringBuilder();
		sb.append(className);
		if(!"".equals(className.trim()))sb.append(" ");
		sb.append(DEFAULT_CLASSNAME);
		return sb.toString();
	}
	
	public void init(XMap view, SparkContext context) throws Exception{
		super.init(view, context);
//		context.addStyleSheet("grid/Grid-min.css");
//		context.addJavaScript("grid/Grid.js");
		
		
		boolean hasToolBar = creatToolBar(view,context);
		boolean hasFooterBar = createFooterBar(view.getChild(PROPERTITY_COLUMNS));
		boolean hasNavBar = createNavgationToolBar(view,context);
		
		String style = "";
		if(hasToolBar){
			style += "border-top:none;";
		}
		if(hasNavBar||hasFooterBar){
			style += "border-bottom:none;";
		}
		Integer height = (Integer)context.get(PROPERTITY_HEIGHT);
		int sh = 0;
		if(hasToolBar) sh +=25;
		if(hasFooterBar) sh +=25;
		if(hasNavBar) sh +=26;
		context.put(TABLE_HEIGHT, new Integer(height.intValue()-sh));
		String rowRenderer = view.getString(PROPERTITY_ROW_RENDERER);
		if(rowRenderer!=null) context.addJsonConfig(PROPERTITY_ROW_RENDERER, rowRenderer);
		boolean autoFocus = view.getBoolean(PROPERTITY_AUTO_FOCUS, true);
		if(!autoFocus) context.addJsonConfig(PROPERTITY_AUTO_FOCUS, new Boolean(autoFocus));
		
		
		context.put(PROPERTITY_SHOW_HEAD, view.getBoolean(PROPERTITY_SHOW_HEAD,true));	
		context.addJsonConfig(PROPERTITY_FOCUS_ROW, view.getBoolean(PROPERTITY_FOCUS_ROW,true));
		context.addJsonConfig(PROPERTITY_LISTEN_MOUSE_WHEEL, view.getBoolean(PROPERTITY_LISTEN_MOUSE_WHEEL,false));
		context.addJsonConfig(PROPERTITY_STRIPE_ROWS, view.getBoolean(PROPERTITY_STRIPE_ROWS,true));
		context.addJsonConfig(PROPERTITY_AUTO_PAGE_SIZE, view.getBoolean(PROPERTITY_AUTO_PAGE_SIZE, false));
		processSelectable(view,context);
		createGridColumns(view,context);
		
		if(hasFooterBar)creatFooterBar(context);
		
		context.put("gridStyle", style);		
		createGridEditors(view,context);
	}
	
	private void processSelectable(XMap view,SparkContext context){
		boolean selectable = false;
		String selectionmodel = DataSet.DEFAULT_SELECTION_MODEL;
		String bt = view.getString(PROPERTITY_BINDTARGET);
		XMap ds = context.getDataSet(bt);
		if(ds !=null) {
			selectable = ds.getBoolean(DataSet.PROPERTITY_SELECTABLE, false);
			selectionmodel = ds.getString(DataSet.PROPERTITY_SELECTION_MODEL, DataSet.DEFAULT_SELECTION_MODEL);
		}
		boolean showRowNumber = view.getBoolean(PROPERTITY_SHOW_ROWNUMBER,false);
		context.put(PROPERTITY_SHOW_ROWNUMBER, showRowNumber);
		context.put(DataSet.PROPERTITY_SELECTABLE, selectable);
		context.put(DataSet.PROPERTITY_SELECTION_MODEL, selectionmodel);
//		context.addJsonConfig(PROPERTITY_SHOW_ROWNUMBER, showRowNumber);
		context.addJsonConfig(DataSet.PROPERTITY_SELECTABLE, selectable);
		context.addJsonConfig(DataSet.PROPERTITY_SELECTION_MODEL, selectionmodel);
	}
	
	@SuppressWarnings("unchecked")
	private void createGridColumns(XMap view,SparkContext context){
		List<XMap> colist = new ArrayList<XMap>(); 
		List cols = new ArrayList();
		Map lkpro = new HashMap();
		lkpro.put(LOCK_WIDTH, new Integer(0));
		
		lkpro.put(ROW_SPAN, new Integer(1));
		Map ukpro = new HashMap();
		ukpro.put(ROW_SPAN, new Integer(1));
		
		String bindTarget = view.getString(PROPERTITY_BINDTARGET);
		String defaultSortField = null;
		String defaultSortType = null;
		XMap ds = context.getDataSet(bindTarget);
		if(ds != null){
			defaultSortField = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_FIELD);
			defaultSortType = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_TYPE,"desc");
		}
		
		
		XMap columns = view.getChild(PROPERTITY_COLUMNS);
		
		List lks = new ArrayList();
		List uks = new ArrayList();
		
		List locks = new ArrayList();
		List unlocks = new ArrayList();
		int maxRow =1;
		boolean selectable = ((Boolean)context.get(DataSet.PROPERTITY_SELECTABLE)).booleanValue();
		boolean showRowNumber = ((Boolean)context.get(PROPERTITY_SHOW_ROWNUMBER)).booleanValue();
		Integer height = (Integer)context.get(TABLE_HEIGHT);
		Integer width = (Integer)context.get(PROPERTITY_WIDTH);
//		Integer viewWidth = view.getInt(PROPERTITY_WIDTH);
		float bl = 1;
		//判断,如果column的宽度之和小于总宽度就同比放大  超过就不放大
		//if(viewWidth!=null && viewWidth.intValue() !=0) {
			int tcw = 0,acw = 0;//tcw 配置的列宽度总和  acw 非自适应的列宽度总和
			Iterator ct = columns.getChildIterator();
			while(ct.hasNext()){
				XMap column = (XMap)ct.next();
				int cw = column.getInt(PROPERTITY_WIDTH, COLUMN_WIDTH);
				boolean adp = column.getBoolean(COLUMN_PROPERTITY_ADAPTIVE, false);
				tcw += cw;
				if(!adp) acw += cw;
			}
			int scrollAndSelectWidth = 20;
			if(selectable) scrollAndSelectWidth += 25;
			if(showRowNumber) scrollAndSelectWidth += 35;
			if(tcw < (width-20)) {
				bl = (width.floatValue() - acw - scrollAndSelectWidth)/(tcw-acw);//bl = (width.floatValue() - acw)/(viewWidth.floatValue()-acw);
			}
			if (bl <1) bl = 1;
		//}
		
		
		if(columns != null) {
			boolean lockBox = view.getBoolean(PROPERTITY_LOCK_ROWBOX, true);
			List ks = lockBox ? lks : uks;
			if(showRowNumber) {
				XMap column = new XMap("column");
				column.setNameSpaceURI(DEFAULT_NAME_SPACE);
				column.putBoolean(COLUMN_PROPERTITY_LOCK,lockBox);
				column.putInt(PROPERTITY_WIDTH, 35);
				column.putString(COLUMN_PROPERTITY_ALIGN, "center");
				column.putBoolean(COLUMN_PROPERTITY_RESIZABLE,false);
				column.putBoolean(COLUMN_PROPERTITY_SORTABLE,false);
				column.putString(PROPERTITY_PROMPT,"No");
				column.putBoolean(COLUMN_PROPERTITY_ADAPTIVE,false);
				column.putString(COLUMN_PROPERTITY_RENDERER, "Spark.RowNumberRenderer");
				column.putString(COLUMN_TYPE,TYPE_ROW_NUMBER);
				ks.add(column);
			}
			
			String selectmodel = (String)context.get(DataSet.PROPERTITY_SELECTION_MODEL);
			if(selectable) {
				XMap column = new XMap("column");
				column.setNameSpaceURI(DEFAULT_NAME_SPACE);
				column.putBoolean(COLUMN_PROPERTITY_LOCK,lockBox);
				column.putInt(PROPERTITY_WIDTH, 25);
				column.putBoolean(COLUMN_PROPERTITY_RESIZABLE,false);
				column.putBoolean(COLUMN_PROPERTITY_SORTABLE,false);
				if("multiple".equals(selectmodel)) {
					column.putString(COLUMN_TYPE,TYPE_ROW_CHECKBOX);
				}else{
					column.putString(COLUMN_TYPE,TYPE_ROW_RADIO);
				}
				ks.add(column);
			}
			
			Iterator cit = columns.getChildIterator();
			while(cit.hasNext()){
				XMap column = (XMap)cit.next();
				boolean isLock = column.getBoolean(COLUMN_PROPERTITY_LOCK, false);
				if(isLock){
					lks.add(column);
				}else{
					uks.add(column);
				}
			}
			
			processColumns(null, lks, locks, lkpro);
			processColumns(null, uks, unlocks, ukpro);
			int lr = ((Integer)lkpro.get(ROW_SPAN)).intValue();
			int ur = ((Integer)ukpro.get(ROW_SPAN)).intValue();
			
			if(ur >= lr){			
				maxRow = ur;
				ukpro.put(MAX_ROWS, new Integer(maxRow));
				ukpro.put(ROW_HEIGHT, new Integer(DEFALUT_HEAD_HEIGHT));
				lkpro.put(MAX_ROWS, new Integer(maxRow));
				lkpro.put(ROW_HEIGHT, lr == 0 ? new Integer(DEFALUT_HEAD_HEIGHT) : new Integer(ur*DEFALUT_HEAD_HEIGHT/lr));
			} else{
				maxRow = lr;
				lkpro.put(MAX_ROWS, new Integer(maxRow));
				ukpro.put(MAX_ROWS, new Integer(maxRow));
				lkpro.put(ROW_HEIGHT, new Integer(DEFALUT_HEAD_HEIGHT));
				ukpro.put(ROW_HEIGHT, ur == 0 ? new Integer(DEFALUT_HEAD_HEIGHT) : new Integer(lr*DEFALUT_HEAD_HEIGHT/ur));
			}
			
			
			List lkFirstList = (List)lkpro.get("l1");
			if(lkFirstList!=null) {
				Iterator lfit = lkFirstList.iterator();
				while(lfit.hasNext()){
					XMap column = (XMap)lfit.next();
					column.put(ROW_SPAN, lkpro.get(MAX_ROWS));
					addRowSpan(column);
				}
			}
			
			
			List ukFirstList = (List)ukpro.get("l1");
			if(ukFirstList!=null) {
				Iterator ufit = ukFirstList.iterator();
				while(ufit.hasNext()){
					XMap column = (XMap)ufit.next();
					column.put(ROW_SPAN, ukpro.get(MAX_ROWS));
					addRowSpan(column);
				}
			}
			cols.addAll(locks);
			cols.addAll(unlocks);
			Iterator it = cols.iterator();
			while(it.hasNext()){
				XMap column = (XMap)it.next();
				if(column.getChilds() == null){
					String dataindex = column.getString(COLUMN_PROPERTITY_NAME,"");
					if(!"".equals(dataindex)) column.putString(COLUMN_PROPERTITY_NAME, dataindex);
					if(column.getBoolean(COLUMN_PROPERTITY_LOCK, false))column.putBoolean(COLUMN_PROPERTITY_LOCK, column.getBoolean(COLUMN_PROPERTITY_LOCK, false));
					if(column.getBoolean(COLUMN_PROPERTITY_HIDDEN, false))column.putBoolean(COLUMN_PROPERTITY_HIDDEN, column.getBoolean(COLUMN_PROPERTITY_HIDDEN, false));
					if(!column.getBoolean(COLUMN_PROPERTITY_RESIZABLE, true))column.putBoolean(COLUMN_PROPERTITY_RESIZABLE, column.getBoolean(COLUMN_PROPERTITY_RESIZABLE, true));
					if(column.getBoolean(COLUMN_PROPERTITY_SHOW_TITLE, false))column.putBoolean(COLUMN_PROPERTITY_SHOW_TITLE, column.getBoolean(COLUMN_PROPERTITY_SHOW_TITLE, false));
					if(column.getBoolean(COLUMN_PROPERTITY_SORTABLE, false))column.putBoolean(COLUMN_PROPERTITY_SORTABLE, column.getBoolean(COLUMN_PROPERTITY_SORTABLE, false));
					
					float cwidth = column.getInt(PROPERTITY_WIDTH, COLUMN_WIDTH);
					boolean adp = column.getBoolean(COLUMN_PROPERTITY_ADAPTIVE, false);
					String type = column.getString(COLUMN_TYPE);
					if(!"rowcheck".equals(type) && !"rowradio".equals(type) && adp && !"rownumber".equals(type))cwidth = cwidth*bl;
					column.putInt(PROPERTITY_WIDTH, Math.round(cwidth));
					String editor = column.getString(COLUMN_PROPERTITY_EDITOR, "");
					if(isCheckBoxEditor(editor, view)){
						column.putString(COLUMN_TYPE, TYPE_CELL_CHECKBOX);
					}
					if(dataindex.equals(defaultSortField)){
						column.putString("sortType",defaultSortType.toLowerCase());
					}
					
					colist.add(column);
				}
			}		
		}
		boolean showHead = (Boolean)context.get(PROPERTITY_SHOW_HEAD);
		
		context.put(PROPERTITY_BINDTARGET, bindTarget);
		context.put(HEAD_HEIGHT, new Integer(maxRow*DEFALUT_HEAD_HEIGHT));
		context.put(LOCK_COLUMNS, locks);
		context.put(UNLOCK_COLUMNS, unlocks);
		context.put(HTML_LOCKAREA, generateLockArea(locks, lkpro, context, bindTarget));
		if(showHead == true) context.put(HTML_UNLOCKAREA, generateUnlockArea(unlocks, ukpro,context, bindTarget));
		Integer lockWidth = (Integer)lkpro.get(LOCK_WIDTH);
		context.put(LOCK_WIDTH, lockWidth);
		context.put(UNLOCK_WIDTH, new Integer(width.intValue()-lockWidth.intValue()));
		
		context.put(BODY_HEIGHT, (showHead == true) ? (height.intValue()-maxRow*DEFALUT_HEAD_HEIGHT) : height);
		
		context.addJsonConfig("maxRow", maxRow);
		context.addJsonConfig(PROPERTITY_COLUMNS, colist);
		context.addJsonConfig(PROPERTITY_WIDTH, context.get(PROPERTITY_WIDTH));
		context.addJsonConfig(PROPERTITY_HEIGHT, context.get(PROPERTITY_HEIGHT));
	}
	
	@SuppressWarnings("unchecked")
	private void createGridEditors(XMap view, SparkContext context) throws Exception{
		XMap editors = view.getChild(PROPERTITY_EDITORS);
		StringBuilder sb = new StringBuilder();
		if(editors != null && editors.getChilds() != null) {
			Iterator it = editors.getChildIterator();
			while(it.hasNext()){
				XMap editor = (XMap)it.next();
				editor.put(PROPERTITY_STYLE, "position:absolute;left:-1000px;top:-1000px;");
				sb.append(SparkBuilder.build(editor,context));
			}
		}
		context.put("editors", sb.toString());
	}
	
	@SuppressWarnings("unchecked")
	private boolean isCheckBoxEditor(String id, XMap view){
		boolean isChecBox = false;
		XMap editors = view.getChild(PROPERTITY_EDITORS);
		if(editors != null && editors.getChilds() != null) {
			Iterator it = editors.getChildIterator();
			while(it.hasNext()){
				XMap editor = (XMap)it.next();
				String eid = editor.getString(PROPERTITY_ID,"");
				if(id.equals(eid)&& "checkBox".equals(editor.getName())){
					isChecBox = true;
					break;
				}
			}
		}
		return isChecBox;
	}
	
	@SuppressWarnings("unchecked")
	private boolean creatToolBar(XMap view, SparkContext context) throws IOException{
		
		XMap toolbar = view.getChild(PROPERTITY_TOOLBAR);
		String dataset = view.getString(PROPERTITY_BINDTARGET);
		
		StringBuilder sb = new StringBuilder();
		boolean hasToolBar = false;
		if(toolbar != null && toolbar.getChilds() != null) {
			hasToolBar = true;
			XMap tb = new XMap(PROPERTITY_TOOLBAR);
			tb.setNameSpaceURI(DEFAULT_NAME_SPACE);
			Integer width = (Integer)context.get(PROPERTITY_WIDTH);
			String id = (String)context.get(PROPERTITY_ID);
			tb.put(PROPERTITY_ID, id+"_tb");
			tb.put(PROPERTITY_WIDTH, new Integer(width.intValue()));
			tb.put(PROPERTITY_CLASSNAME, "grid-toolbar");
			Iterator it = toolbar.getChildIterator();
			while(it.hasNext()){
				XMap item = (XMap)it.next();
				if("button".equals(item.getName())){
					String type = item.getString("type");
					if(!"".equals(type)){
						StringBuilder tsb = new StringBuilder();
						if("add".equalsIgnoreCase(type)){
							tsb.append("function(){$('").append(dataset).append("').create()}");
							item = createButton(item,"新增","grid-add","background-position:0px 0px;",tsb.toString());
						}else if("delete".equalsIgnoreCase(type)){
							tsb.append("function(){$('").append(id).append("').remove()}");
							item = createButton(item,"删除","grid-delete","background-position:0px -35px;",tsb.toString());
						}else if("save".equalsIgnoreCase(type)){
							tsb.append("function(){$('").append(dataset).append("').submit()}");
							item = createButton(item,"保存","grid-save","background-position:0px -17px;",tsb.toString());
						}
					}
				}
				tb.addChild(item);
			}
			sb.append("<tr><td>");
			try {
				sb.append(SparkBuilder.build(tb,context));
			} catch (Exception e) {
				throw new IOException(e.getMessage());
			}
			sb.append("</td></tr>");
		}
		context.put(PROPERTITY_TOOLBAR, sb.toString());
		return hasToolBar;
	}
	
	private XMap createButton(XMap button, String text, String clz,String style,String function){
		if("".equals(button.getString(XButton.PROPERTITY_ICON,""))){
			button.put(PROPERTITY_WIDTH, button.getInt(PROPERTITY_WIDTH, new Integer(55)));
			button.put(XButton.PROPERTITY_TEXT_STYLE, "padding-left:15px;");
			button.put(XButton.PROPERTITY_TEXT_CLASS, clz);
			button.put(XButton.PROPERTITY_BUTTON_STYLE, style);
		}
		button.put(XButton.PROPERTITY_TEXT,button.getString(XButton.PROPERTITY_TEXT, text));
		button.put(XButton.PROPERTITY_CLICK,button.getString(XButton.PROPERTITY_CLICK, function));
		return button;
	}
	
//	public boolean hasFooterBar(BuildSession session, ViewContext context){
//		boolean hasFooterBar = false;
//		XMap view = context.getView();
//		GridConfig gc = getInstance(view);
//		XMap columns = gc.getColumns();
//		List childs = columns.getChilds();
//		if(childs!=null){
//			Iterator it = childs.iterator();
//			while(it.hasNext()){
//				XMap column = (XMap)it.next();
//				GridColumnConfig gcc = COLUMN_getInstance(column);
//				String footerRenderer = gcc.getFooterRenderer();
//				if(footerRenderer!=null){
//					hasFooterBar = true;
//					break;
//				}
//			}
//		}
//		return hasFooterBar;		
//	}
	
	@SuppressWarnings("unchecked")
	public boolean createFooterBar(XMap column){
		boolean hasFooterBar = false;
		String footerRenderer = column.getString(COLUMN_PROPERTITY_FOOTER_RENDERER);
		if(footerRenderer!=null){
			return true;
		}
		List childs = column.getChilds();
		if(childs!=null){
			Iterator it = childs.iterator();
			while(it.hasNext()){
				XMap col = (XMap)it.next();
				if(createFooterBar(col)){
					hasFooterBar = true;
					break;
				}
			}
		}
		return hasFooterBar;		
	} 
	
	@SuppressWarnings("unchecked")
	private void creatFooterBar(SparkContext context) throws IOException{
		int lockWidth = ((Integer)context.get(LOCK_WIDTH)).intValue();
		StringBuilder sb = new StringBuilder();
		sb.append("<tr><td><div class='grid-footerbar' stype='grid.fb' style='width:").append(context.get(PROPERTITY_WIDTH)).append("px'>");			
		if(lockWidth!=0){
			sb.append("<div stype='grid.lf' style='float:left;width:").append(lockWidth-1).append("px'>");//class='grid-la' 
			List locks = (List)context.get(LOCK_COLUMNS);
			if(locks!=null){
				sb.append("<table cellSpacing='0' cellPadding='0' border='0' stype='fb.lbt' ");
				Iterator it = locks.iterator();
				sb.append(createFooterBarTable(context,it,false));
			}
			sb.append("</div>");
		}

		sb.append("<div class='grid-ua' stype='grid.uf' style='width:").append(context.get(UNLOCK_WIDTH)).append("px'>");
		List unlocks = (List)context.get(UNLOCK_COLUMNS);
		if(unlocks!=null){
			sb.append("<table cellSpacing='0' cellPadding='0' border='0' stype='fb.ubt' ");
			Iterator it = unlocks.iterator();
			sb.append(createFooterBarTable(context,it,true));
		}
		sb.append("</div>");
		sb.append("</div></td></tr>");
		context.put(FOOTER_BAR, sb.toString());		
	}
	
	@SuppressWarnings("unchecked")
	private String createFooterBarTable(SparkContext context,Iterator it,boolean hasSpan){
		int i = 0,w = 0;
		StringBuilder sb = new StringBuilder();
		StringBuilder tb = new StringBuilder();
		StringBuilder th = new StringBuilder();
		th.append("<tr class='grid-hl'");
		if(isIE6OrIE7(context)) sb.append(" style='display:none'");
		sb.append(">");
		while(it.hasNext()){
			XMap column = (XMap)it.next();
			if(column.getChilds()!=null) continue;
			int cw = column.getInt(PROPERTITY_WIDTH,150);
			String name = column.getString(COLUMN_PROPERTITY_NAME);
			w += cw;
			th.append("<th style='width:").append(cw).append("px;' dataindex='").append(name).append("'></th>");
			String align = column.getString(COLUMN_PROPERTITY_ALIGN,DEFAULT_COLUMN_ALIGN);
			tb.append("<td style='text-align:").append(align).append(";");
//			tb.append(((i==0) ? "border:none;" : "")+"'");
			tb.append("'");
			if(name!=null) tb.append("dataindex='").append(name).append("'");
			tb.append(">&#160;</td>");
			i++;
		}
		if(hasSpan)th.append("<th style='width:17px;'></th>");
		sb.append("style='width:").append(w).append("px;table-layout:fixed;'>");//margin-right:20px;padding-right:20px;
		sb.append(th.toString()).append("</tr><tr>");
		
		sb.append(tb.toString());
		sb.append("</tr></table>");
		return sb.toString();
	}
	
	private boolean createNavgationToolBar(XMap view, SparkContext context) throws Exception{
		boolean hasNavBar = false;
		StringBuilder sb = new StringBuilder();
		String dataset = view.getString(PROPERTITY_BINDTARGET);
		
		hasNavBar = view.getBoolean(PROPERTITY_NAVBAR, false);
		if(hasNavBar){
			hasNavBar = true;
			XMap navbar = new XMap(NavBar.TAG_NAME);
			navbar.setNameSpaceURI(DEFAULT_NAME_SPACE);
			Integer width = (Integer)context.get(PROPERTITY_WIDTH);
			
			
//			Integer width = Integer.valueOf(view.getString(PROPERTITY_WIDTH));
			navbar.put(PROPERTITY_ID, context.get(PROPERTITY_ID)+"_navbar");
			navbar.put(PROPERTITY_WIDTH, new Integer(width.intValue()));
			navbar.put(PROPERTITY_CLASSNAME, "grid-navbar");
//			navbar.put(PROPERTITY_STYLE, "border:none;border-top:1px solid #cccccc;");
			navbar.put(NavBar.PROPERTITY_NAVBAR_TYPE, view.getString(NavBar.PROPERTITY_NAVBAR_TYPE, "complex"));
			navbar.put(NavBar.PROPERTITY_DATASET, dataset);
			navbar.put(NavBar.PROPERTITY_PAGE_SIZE_EDITABLE,new Boolean(view.getBoolean(NavBar.PROPERTITY_PAGE_SIZE_EDITABLE,true)));
			sb.append("<tr><td style=\"border-top:1px solid #ccc\">");
			sb.append(SparkBuilder.build(navbar,context));
			sb.append("</td></tr>");
			context.put(PROPERTITY_NAVBAR, sb.toString());
		}
		return hasNavBar;
	}
	
	
	@SuppressWarnings("unchecked")
	private void processColumns(XMap parent, List children, List cols, Map pro){
		Iterator it = children.iterator();
		while(it.hasNext()){
			XMap column = (XMap)it.next();
			int level;
			if(parent == null){
				level = 1;				
			}else{
				level = parent.getInt("_level").intValue() + 1;
			}
			int rows = ((Integer)pro.get(ROW_SPAN)).intValue();
			if(level>rows)pro.put(ROW_SPAN, new Integer(level));
			StringBuilder sb = new StringBuilder();
			sb.append("l").append(level);
			column.put("_level", new Integer(level));
			column.put("_parent", parent);
			List hlist = (List)pro.get(sb.toString());
			if(hlist == null){
				hlist = new ArrayList();
				pro.put(sb.toString(), hlist);
			}
			hlist.add(column);
			cols.add(column);
			if(column.getChilds() != null && column.getChilds().size() >0){
				processColumns(column, column.getChilds(), cols, pro);
			}else{
				addColSpan(column);
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	private void addRowSpan(XMap column){
		List children = column.getChilds();
		Integer psp = column.getInt(ROW_SPAN);
		if(children != null && children.size() >0){
			minusRowSpan(column);
			Iterator it = children.iterator();
			while(it.hasNext()){
				XMap child = (XMap)it.next();
				child.put(ROW_SPAN, new Integer(psp.intValue()-1));
				addRowSpan(child);
			}
		}
		
	}
	
	private void minusRowSpan(XMap column){
		if(column == null)return;
		Integer rowspan = column.getInt(ROW_SPAN);
		if(rowspan != null){
			int cs = Math.max(rowspan.intValue() -1,1);
			column.put(ROW_SPAN, new Integer(cs));
		}
		XMap parent = (XMap)column.get("_parent");
		if(parent != null){			
			minusRowSpan(parent);
		}
		
	}
	
	
	private void addColSpan(XMap column){
		if(column == null)return;
		XMap parent = (XMap)column.get("_parent");
		if(parent != null){
			Integer colspan = parent.getInt(COL_SPAN);
			if(colspan == null){
				parent.put(COL_SPAN, new Integer(1));
			}else{
				int cs = colspan.intValue() +1;
				parent.put(COL_SPAN, new Integer(cs));
			}
		}
		addColSpan(parent);
	}

	
	@SuppressWarnings("unchecked")
	private String generateLockArea(List columns, Map pro,SparkContext context, String dataSet){
		StringBuilder sb = new StringBuilder();
		StringBuilder th = new StringBuilder();
		boolean hasLockColumn = false;
		Integer rows = (Integer)pro.get(ROW_SPAN);
		Iterator it = columns.iterator();
		int lockWidth = 0;
		while(it.hasNext()){
			XMap column = (XMap)it.next();
			if(column.getBoolean(COLUMN_PROPERTITY_LOCK, false)){
				hasLockColumn = true;
				List children = column.getChilds();
				if(children == null){
					float cwidth = column.getInt(PROPERTITY_WIDTH, COLUMN_WIDTH);
					th.append("<th style='width:").append(cwidth).append("px;' dataindex='").append(column.getString(COLUMN_PROPERTITY_NAME,"")).append("'></th>");
					lockWidth +=cwidth;				
				}				
			}
		}
		
		pro.put(LOCK_WIDTH, new Integer(lockWidth));
		String defaultSortField = null;
		String defaultSortType = null;
		XMap ds = context.getDataSet(dataSet);
		if(ds != null){
			defaultSortField = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_FIELD);
			defaultSortType = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_TYPE);
		}
		
		if(hasLockColumn){
			sb.append("<DIV class='grid-la' stype='grid.lc' style='width:").append(lockWidth).append("px;'>");
			sb.append("<DIV class='grid-lh' stype='grid.lh' unselectable='on' onselectstart='return false;' style='height:").append(rows.intValue()*((Integer)pro.get(ROW_HEIGHT)).intValue()).append("px;'>");
			
			StringBuilder hsb = new StringBuilder();
			for(int i=1;i<=rows.intValue();i++){
				List list = (List)pro.get("l"+i);
				hsb.append("<TR height=").append((Integer)pro.get(ROW_HEIGHT)).append(">");
				if(list!=null) {
					Iterator lit = list.iterator();
					while(lit.hasNext()){
						XMap column = (XMap)lit.next();
						String ct =  column.getString(COLUMN_TYPE);
						if(TYPE_ROW_CHECKBOX.equals(ct)){
							hsb.append("<TD class='rbox' align='center' stype='grid.rowcheck'><div stype='grid.headcheck' class='grid-ckb'><div class='s-ckb-box'></div></div></TD>");
						}else if(TYPE_ROW_RADIO.equals(ct)) {
							hsb.append("<TD class='rbox' stype='grid.rowradio'><div>&nbsp;</div></TD>");
						}else{
							boolean hidden =  column.getBoolean(COLUMN_PROPERTITY_HIDDEN, false);
							if(!hidden){
								String headTitle = getFieldPrompt(column, context, dataSet);
								String name = column.getString(COLUMN_PROPERTITY_NAME,"");
								
								boolean sortable = column.getBoolean(COLUMN_PROPERTITY_SORTABLE,false);
								String sortCss = "";
								if(name.equals(defaultSortField)){
									sortCss = "DESC".equalsIgnoreCase(defaultSortType) ? "class='grid-sort grid-desc'" : "class='grid-sort grid-asc'";
								}else if(sortable) {
									sortCss = "class='grid-sort'";
								}
//								headTitle = session.getLocalizedPrompt(headTitle);
								hsb.append("<TD class='grid-hc' stype='grid.head' colspan='").append(column.getInt(COL_SPAN,1)).append("' rowspan='").append(column.getInt(ROW_SPAN)).append("' dataindex='").append(name).append("'><div "+sortCss+">").append(headTitle).append("</div></TD>");
							}
						}
					}
				}
				hsb.append("</TR>");
			}
			
			sb.append("<TABLE cellSpacing='0' stype='grid.lht' cellPadding='0' border='0' style='width:").append(lockWidth).append("px'><TBODY>");//margin-right:20px;padding-right:20px;
			sb.append("<TR class='grid-hl'");
			if(isIE6OrIE7(context)) sb.append(" style='display:none'");
			sb.append(">");
			sb.append(th.toString());
			sb.append("</TR>");
			sb.append(hsb);
			sb.append("</TBODY></TABLE>");
			
			Integer height = (Integer)context.get(TABLE_HEIGHT);
			sb.append("</DIV><DIV class='grid-lb' stype='grid.lb' style='width:100%;height:").append((height.intValue()-rows.intValue()*((Integer)pro.get(ROW_HEIGHT)).intValue())).append("px'>");
			sb.append("</DIV></DIV>");
		}
		return sb.toString();
	}
	
	@SuppressWarnings("unchecked")
	private String generateUnlockArea(List columns, Map pro,SparkContext context, String dataSet){
		StringBuilder sb = new StringBuilder();
		StringBuilder th = new StringBuilder();
		
		Integer rows = (Integer)pro.get(ROW_SPAN);
		Iterator it = columns.iterator();
		int unlockWidth = 0;
		while(it.hasNext()){
			XMap column = (XMap)it.next();
			List children = column.getChilds();
			if(children == null){
				float cwidth = column.getInt(PROPERTITY_WIDTH, COLUMN_WIDTH);
				th.append("<th style='width:").append(cwidth).append("px;' dataindex='").append(column.getString(COLUMN_PROPERTITY_NAME,"")).append("'></th>");
				unlockWidth +=cwidth;				
			}
		}
		
		sb.append("<TABLE cellSpacing='0' stype='grid.uht' cellPadding='0' border='0' style='width:").append(unlockWidth).append("px'><TBODY>");
		sb.append("<TR class='grid-hl'");
		if(isIE6OrIE7(context)) sb.append(" style='display:none'");
		sb.append(">");
		sb.append(th.toString());
		sb.append("<TH WIDTH='20'> </TH>");
		sb.append("</TR>");
		
		
		String defaultSortField = null;
		String defaultSortType = null;
		XMap ds = context.getDataSet(dataSet);
		if(ds != null){
			defaultSortField = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_FIELD);
			defaultSortType = ds.getString(DataSet.PROPERTITY_DEFAULT_SORT_TYPE);
		}
		StringBuilder hsb = new StringBuilder();
		for(int i=1;i<=rows.intValue();i++){
			List list = (List)pro.get("l"+i);
			
			hsb.append("<TR height=").append((Integer)pro.get(ROW_HEIGHT)).append(">");
			if(list!=null) {
				Iterator lit = list.iterator();
				while(lit.hasNext()){
					XMap column = (XMap)lit.next();
					String ct =  column.getString(COLUMN_TYPE);
					if(TYPE_ROW_CHECKBOX.equals(ct)){
						hsb.append("<TD class='rbox' align='center' stype='grid.rowcheck'><div stype='grid.headcheck' class='grid-ckb'><div class='s-ckb-box'></div></div></TD>");
					}else if(TYPE_ROW_RADIO.equals(ct)) {
						hsb.append("<TD class='rbox' stype='grid.rowradio'><div>&nbsp;</div></TD>");
					}else{
						boolean hidden =  column.getBoolean(COLUMN_PROPERTITY_HIDDEN, false);
						if(!hidden){
							String headTitle = getFieldPrompt(column, context, dataSet);
							String name = column.getString(COLUMN_PROPERTITY_NAME,"");
							boolean sortable = column.getBoolean(COLUMN_PROPERTITY_SORTABLE,false);
							String sortCss = "";
							if(name.equals(defaultSortField)){
								sortCss = "DESC".equalsIgnoreCase(defaultSortType) ? "class='grid-sort grid-desc'" : "class='grid-sort grid-asc'";
							}else if(sortable) {
								sortCss = "class='grid-sort'";
							}
							hsb.append("<TD class='grid-hc' stype='grid.head'  colspan='").append(column.getInt(COL_SPAN,1)).append("' rowspan='").append(column.getInt(ROW_SPAN)).append("' dataindex='").append(name).append("'><div "+sortCss+">").append(headTitle).append("</div></TD>");
						}
					}
				}
			}
			hsb.append("</TR>");
		}
		sb.append(hsb);
		sb.append("</TBODY></TABLE>");		
		return sb.toString();
	}
	
	
	@SuppressWarnings("unchecked")
	protected String build(SparkContext context){
		Map map = context.getMap();
		StringBuilder sb = new StringBuilder();
		sb.append("<table tabIndex=\"").append(get(map,"tabIndex")).append("\" class=\"").append(get(map,"className")).append("\" id=\"").append(get(map,"id")).append("_wrap\" style=\"").append(get(map,"style")).append("\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" hidefocus>\r");
		sb.append("<tbody>\r");
		sb.append("	").append(get(map,"toolBar"));
		sb.append("	<tr>\r");
		sb.append("		<td class=\"layout-td-cell\">\r");
		sb.append("			<div class=\"s-grid\" id=\"").append(get(map,"id")).append("\" style=\"width:").append(get(map,"width")).append("px;height:").append(get(map,"tableHeight")).append("px;").append(get(map,"gridStyle")).append("\">\r");
		sb.append("				").append(get(map,"lockArea"));
		sb.append("				<div class=\"grid-ua\" stype=\"grid.uc\" style=\"width:").append(get(map,"unlockWidth")).append("px;\">\r");
		Boolean showHead = (Boolean)get(map,"showHead");
		if(showHead) {
			sb.append("					<div class=\"grid-uh\" unselectable=\"on\" onselectstart=\"return false;\" style=\"width:").append(get(map,"unlockWidth")).append("px;-moz-user-select:none;height:").append(get(map,"headHeight")).append("px;\"  stype=\"grid.uh\">\r");
			sb.append("						").append(get(map,"unlockArea"));
			sb.append("					</div>\r");
		}
		sb.append("					<div class=\"grid-ub\" stype=\"grid.ub\" style=\"width:").append(get(map,"unlockWidth")).append("px;height:").append(get(map,"bodyHeight")).append("px;\">\r");
		sb.append("					</div>\r");
		sb.append("				</div>\r");
		sb.append("				<div style=\"clear:both;\"></div>\r");
		sb.append("				<div stype=\"grid.spliter\" class=\"grid-sp\" onselectstart=\"return false;\" unselectable=\"on\" style=\"display:none;\"></div>\r");
		sb.append("			</div>\r");
		sb.append("		</td>\r");
		sb.append("	</tr>\r");
		sb.append("	").append(get(map,"footerBar"));
		sb.append("	").append(get(map,"navBar"));
		sb.append("</tbody>\r");
		sb.append("</table>\r");
		sb.append("<script>new Spark.Grid(").append(get(map,"config")).append(");</script>\r");
		sb.append(get(map,"editors"));
		return sb.toString();
	}
	
}
